package IC.Parser;

import java.lang.Math;

%%
%cup
%class Lexer
%public
%function next_token
%type Token
%line
%scanerror LexicalError
%state YYQUOTE
%state YYLINE_COMMENT
%state YYSECTION_COMMENT

%{
	
	private Token createToken(int tokenID, String tokenName, Object tokenValue, boolean isIdentifier)
	{
		return new Token( yyline + 1, tokenName, tokenID, tokenValue,isIdentifier);
	}
	

	
	private Token CreateIdentifer(int tokenID, String tokenName, Object tokenValue)
	{
		return createToken(tokenID, tokenName, tokenValue, true);
	}
	
	private Token CreateSymbol(int tokenID, String tokenName, Object tokenValue)
	{
		return createToken(tokenID, tokenName, tokenValue, false);
	}

	private LexicalError createError(String errorMsg)
	{
		return new LexicalError(errorMsg,(yyline + 1));
	}

%}

/* Regex Definitions */	

LineTerminator = 			\r|\n|\r\n
WhiteSpace = 				{LineTerminator} | [ \t\f]
LineComment = 				"//" 
SectionComment = 			"/*"
Digit =						[0-9]
Letters = 					[a-zA-Z]
AlphaNumeric =				({Letters}|{Digit}|"_")*
Number = 					"0" | [1-9][0-9]*
IllNumber =					0*{Number} 
StringSpacials =			"\\n" | "\\\\" | "\\\"" | "\\t"
StringChars = 				[ !#-\[\]-\~]
String = 					({StringSpacials} | {StringChars} )* 
ClassIdentifier = 			[A-Z]{AlphaNumeric}
Identifier = 				[a-z]{AlphaNumeric}
IllIdentifier = 			[0-9]{AlphaNumeric}
%%

<YYINITIAL>
{

	/* comments */
	{LineComment} {yybegin(YYLINE_COMMENT);}
	{SectionComment} {yybegin(YYSECTION_COMMENT);}
	
	/* keywords */
	"class"				{ 	return CreateSymbol(sym.CLASS,"CLASS",yytext());  }
	"extends"			{ 	return CreateSymbol(sym.EXTENDS,"EXTENDS",yytext());  }
	"static"			{ 	return CreateSymbol(sym.STATIC,"STATIC",yytext());  }
	"void"				{ 	return CreateSymbol(sym.VOID,"VOID",yytext());  }
	"int"				{ 	return CreateSymbol(sym.INT,"INT",yytext());  }
	"boolean"			{ 	return CreateSymbol(sym.BOOLEAN,"BOOLEAN",yytext());  }
	"string"			{ 	return CreateSymbol(sym.STRING,"STRING",yytext());  }
	"return"		 	{ 	return CreateSymbol(sym.RETURN,"RETURN",yytext());  }
	"if"	 			{ 	return CreateSymbol(sym.IF,"IF",yytext());  }
	"else"	 			{ 	return CreateSymbol(sym.ELSE,"ELSE",yytext());  }
	"while"	 			{ 	return CreateSymbol(sym.WHILE,"WHILE",yytext());  }
	"break"	 			{ 	return CreateSymbol(sym.BREAK,"BREAK",yytext());  }
	"continue"			{ 	return CreateSymbol(sym.CONTINUE,"CONTINUE",yytext());  }
	"this"	 			{ 	return CreateSymbol(sym.THIS,"THIS",yytext());  }
	"new"	 			{ 	return CreateSymbol(sym.NEW,"NEW",yytext());  }
	"length"	 		{ 	return CreateSymbol(sym.LENGTH,"LENGTH",yytext());  }
	"true"	 			{ 	return CreateSymbol(sym.TRUE,"TRUE",yytext());  }
	"false"	 			{ 	return CreateSymbol(sym.FALSE,"FALSE",yytext());  }
	"null"	 			{ 	return CreateSymbol(sym.NULL,"NULL",yytext());  }
	{ClassIdentifier}	{ 	return CreateIdentifer(sym.CLASS_ID,"CLASS_ID",yytext());  }	
	{Identifier}		{ 	return CreateIdentifer(sym.ID,"ID",yytext());  }	
	{Number}			{ 	
							if (Math.abs(Long.parseLong(yytext())) >= (long)Math.pow(2,31))
									throw createError("Lexical error: invalid integer " + yytext());
							
			 				return CreateIdentifer(sym.INTEGER,"INTEGER",yytext());  
			 			}
	{IllNumber}			{	throw createError("Lexical error: nonzero number cannot start with zero '" + yytext() + "'");  }
	{IllIdentifier}		{	throw createError("Lexical error: identifier cannot start with digits '" + yytext() + "'");  }
	\"\"				{	return CreateIdentifer(sym.QUOTE,"QUOTE",yytext()); 	}
	\"					{	yybegin(YYQUOTE); 		}

	/* Symbols */
	"(" 				{ 	return CreateSymbol(sym.LP,"LP",yytext());  }
	")" 				{  	return CreateSymbol(sym.RP,"RP",yytext());  }
	"["					{  	return CreateSymbol(sym.LB,"LB",yytext());  }
	"]"					{  	return CreateSymbol(sym.RB,"RB",yytext());  }
	"{"					{  	return CreateSymbol(sym.LCBR,"LCBR",yytext());  }
	"}"					{  	return CreateSymbol(sym.RCBR,"RCBR",yytext());  }
	"+"					{  	return CreateSymbol(sym.PLUS,"PLUS",yytext());  }
	"-"					{  	return CreateSymbol(sym.MINUS,"MINUS",yytext());  }
	"*"					{  	return CreateSymbol(sym.MULTIPLY,"MULTIPLY",yytext());  }
	"/"					{  	return CreateSymbol(sym.DIVIDE,"DIVIDE",yytext());  }
	"%"					{  	return CreateSymbol(sym.MOD,"MOD",yytext());  }
	">="				{  	return CreateSymbol(sym.GTE,"GTE",yytext());  }
	">"					{  	return CreateSymbol(sym.GT,"GT",yytext());  }
	"<="				{  	return CreateSymbol(sym.LTE,"LTE",yytext());  }
	"<"					{  	return CreateSymbol(sym.LT,"LT",yytext());  }
	"!="				{  return CreateSymbol(sym.NEQUAL,"NEQUAL",yytext());  }
	"=="				{  return CreateSymbol(sym.EQUAL,"EQUAL",yytext());  }
	"="					{  return CreateSymbol(sym.ASSIGN,"ASSIGN",yytext());  }
	"."					{  return CreateSymbol(sym.DOT,"DOT",yytext());  }
	","					{  return CreateSymbol(sym.COMMA,"COMMA",yytext());  }
	";"					{  return CreateSymbol(sym.SEMI,"SEMI",yytext());  }
	"!"					{  return CreateSymbol(sym.LNEG,"LNEG",yytext());  }	
	"&&"				{  return CreateSymbol(sym.LAND,"LAND",yytext());  }
	"||"				{  return CreateSymbol(sym.LOR,"LOR",yytext());  }
	{WhiteSpace} 		{   }
	<<EOF>> 			{	return CreateSymbol(sym.EOF,"EOF","END_OF_FILE_ERROR");  }
	.					{	throw createError("Lexical error: illegal character '" + yytext() + "'"); }
}

<YYQUOTE>
{
	{String}			{	return CreateIdentifer(sym.QUOTE,"QUOTE","" + yytext() + ""); 	}
	\"					{	yybegin(YYINITIAL);									}	
	.					{	throw createError("Lexical error: illegal quote"); 	}	
	<<EOF>> 			{	throw createError("Lexical error: unclosed string");}

}
 
<YYLINE_COMMENT>
{
	[^\n] {}
	<<EOF>> {	return CreateSymbol(sym.EOF,"EOF",yytext());  }
    [\n] {yybegin(YYINITIAL);}
    
}
<YYSECTION_COMMENT>
{
	[^\*] {}
	"*/" {yybegin(YYINITIAL);}
	"*" {}
	<<EOF>> 		{	throw createError("Lexical error: unclosed comment");}
}

<<EOF>> 			{	throw createError("Lexical error: unknown");}




